import numpy as np
from scipy.optimize import minimize, differential_evolution, NonlinearConstraint
import pandas as pd

df=pd.read_csv('sm.csv')


df['x'] = None
df['xs'] = None
df['gamma'] = None
df['gammas'] = None
df['swl'] = None


wbar = 10
S=10e6

b = 200
mu=0.6
amen=100
f = 4

rr=1.1


checkbar=1000
checkbar1=100
xub=10000000
x1ub=500000



for i in range(len(df)):    
        

    G=df.loc[i,'G']
    p=df.loc[i,'P']
    tau=df.loc[i,'tau']
    xbar=df.loc[i,'xbar']

    c = 0.5411 * p
  
    # Objective function (negative for maximization)
    def objective(vars):
        x, gamma = vars
        return -(wbar + b * (1 - 1 / (gamma * (1 - tau) * (p * x - c * x))) - f * (1 / (1 + xbar / (mu * x))))
     
    def constraint(vars):
        x, gamma = vars
        return 1 - G / ((1 - tau) * (p * x - c * x)) - gamma
     
    # Define bounds
    x_min = G / ((1 - tau) * (p - c)) + 100
    bounds = [(x_min, xub), (0, 1)]  # x in [x_min, 500000], gamma in [0, 1]
    
    # Define Nonlinear Constraint
    nl_constraint = NonlinearConstraint(constraint, 0, np.inf)
    
    # Step 1: Use Global Optimization for Initialization
    def global_optimization():
        result_global = differential_evolution(
            objective, 
            bounds=bounds, 
            constraints=(nl_constraint,),  # Pass the constraint properly
            seed=42
        )
        return result_global.x
    
    # Step 2: Local Optimization Refinement
    def local_optimization(initial_guess):
        options = {
            'maxiter': 1000,
            'ftol': 1e-6,
            'disp': True
        }
        result_local = minimize(
            objective,
            initial_guess,
            bounds=bounds,
            constraints={'type': 'ineq', 'fun': constraint},
            method='SLSQP',
            options=options
        )
        return result_local
    
    # Perform Global Optimization
    initial_guess = global_optimization()
    
    # Perform Local Optimization
    result = local_optimization(initial_guess)
    
    # Check Results
    if result.success:
        optimal_x, optimal_gamma = result.x
        optimal_value = -result.fun
    
    bbar=b*1.2
    
    def objective1(vars):
        x, gamma = vars
        return -(wbar + bbar * (1 - 1 / (gamma * (1 - tau) * (p * x - c * x))) + p * x - c * x+S-amen*x**rr)
    
    def constraint1(vars):
        x, gamma = vars
        return 1 - G / ((1 - tau) * (p * x - c * x)) - gamma
     
    # Define bounds
    x_min1 = G / ((1 - tau) * (p - c)) + 100
    bounds1 = [(x_min1, x1ub), (0, 1)]  # x in [x_min, 500000], gamma in [0, 1]
    
    # Define Nonlinear Constraint
    nl_constraint1 = NonlinearConstraint(constraint1, 0, np.inf)
    
    # Step 1: Use Global Optimization for Initialization
    def global_optimization1():
        result_global = differential_evolution(
            objective1, 
            bounds=bounds1, 
            constraints=(nl_constraint1,),  
            seed=42
        )
        return result_global.x
    
    # Step 2: Local Optimization Refinement
    def local_optimization1(initial_guess):
        options = {
            'maxiter': 1000,
            'ftol': 1e-6,
            'disp': True
        }
        result_local = minimize(
            objective1,
            initial_guess,
            bounds=bounds1,
            constraints={'type': 'ineq', 'fun': constraint1},
            method='SLSQP',
            options=options
        )
        return result_local
    
    # Perform Global Optimization
    initial_guess = global_optimization1()
    
    # Perform Local Optimization
    result1 = local_optimization1(initial_guess)
    
    # Check Results
    if result1.success:
        optimal_x1, optimal_gamma1 = result1.x
        optimal_value1 = -result1.fun

    swl=bbar * (1 / ( optimal_gamma * (1 - tau) * (p *  optimal_x - c *  optimal_x))-1 / ( optimal_gamma1 * (1 - tau) * (p *  optimal_x1 - c *  optimal_x1))) + p *  optimal_x1 - c *  optimal_x1-(p *  optimal_x - c *  optimal_x)+amen*((optimal_x)**rr-(optimal_x1)**rr)
    swlprom=bbar * (1 / ( optimal_gamma * (1 - tau) * (p *  optimal_x - c *  optimal_x))-1 / ( optimal_gamma1 * (1 - tau) * (p *  optimal_x1 - c *  optimal_x1)))
    swlrevenue= p *  optimal_x1 - c *  optimal_x1-(p *  optimal_x - c *  optimal_x)
    swlstock=amen*((optimal_x)**rr-(optimal_x1)**rr)
    
    def u(x):
        gamma=1 - G / ((1 - tau) * (p * x - c * x))    
        return wbar + b * (1 - 1 / (gamma * (1 - tau) * (p * x - c * x))) - f * (1 / (1 + xbar / (mu * x)))
        
    def check(x):
        
        if u(x-checkbar)<=optimal_value and u(x+checkbar)<=optimal_value:
            return 1   
        else:
            return 0
     
    def u1(x):
        gamma=1 - G / ((1 - tau) * (p * x - c * x))    
        return (wbar + bbar * (1 - 1 / (gamma * (1 - tau) * (p * x - c * x))) + p * x - c * x+S-amen*x**rr)
        
    def check1(x):
        if u1(x-checkbar1)<=optimal_value1 and u1(x+checkbar1)<=optimal_value1:
            return 1   
        else:
            return 0
        
        
    print("check(optimal_x)",check(optimal_x))
    print("check1(optimal_x1)",check1(optimal_x1))
    print("xub-optimal_x>1",xub-optimal_x)
    print("x1ub-optimal_x1>1",x1ub-optimal_x1)
            

    
    if  check(optimal_x) and check1(optimal_x1) and xub-optimal_x>1 and x1ub-optimal_x1>1 and optimal_x1<=xbar:
        df.loc[i,'x']=optimal_x
        df.loc[i,'gamma']=optimal_gamma
        
        df.loc[i,'xs']=optimal_x1
        df.loc[i,'gammas']=optimal_gamma1
        
        df.loc[i,'swl']=swl
        df.loc[i,'swlprom']=swlprom
        df.loc[i,'swlrevenue']=swlrevenue
        df.loc[i,'swlstock']=swlstock
        
    else:
        df.loc[i,'x']=None
        df.loc[i,'gamma']=None
        df.loc[i,'xs']=None
        df.loc[i,'gammas']=None
        df.loc[i,'swl']=None
        df.loc[i,'swlprom']=None
        df.loc[i,'swlrevenue']=None
        df.loc[i,'swlstock']=None

df.to_csv('sm_swl.csv', index=False)
